package spynx.desl.runtime.matchinfos.impl;

import spynx.desl.DeslPattern;
import spynx.desl.runtime.IExecutionContext;
import spynx.desl.runtime.IPatternMatchInfo;
import spynx.desl.runtime.impl.ObjectVariable;
import spynx.util.ArgumentSet;

public class PatternMatchInfo extends ObjectVariable implements IPatternMatchInfo {
	
	private CharSequence input, localInput;
	private boolean localInputDirty;
	private int position = 0;
	private int beginPos = -1;
	private int endPos = -1;
	private IExecutionContext context;
	private boolean matched = true;
	private DeslPattern pattern;
	private Object returnedResult;
	private ArgumentSet arguments;
	
	public final static PatternMatchInfo FALSE_MATCHED;
	
	static {
		FALSE_MATCHED = new PatternMatchInfo();
		FALSE_MATCHED.setMatched(false);
	}
	
	public PatternMatchInfo() {
		super(PatternMatchInfo.class.getName());
	}

	@Override
	public CharSequence getInput() {
		return this.input;
	}
	
	protected boolean isLocalInputDirty() {
		return localInputDirty || localInput == null;
	}
	
	@Override
	public CharSequence getLocalInput() {
		if (isLocalInputDirty() && input != null)
			localInput = input.subSequence(getBeginLocation(), getEndLocation());
		return localInput;
	}

	@Override
	public void setInput(CharSequence input) {
		this.input = input;
	}

	@Override
	public int getPosition() {
		return Math.max(position, 0);
	}
	
	@Override
	public int getGlobalPosition() {
		return getPosition() + getBeginLocation();
	}

	@Override
	public int setPosition(int value, int mode) {
		switch (mode) {
		case SEEK_LOCAL_FROM_BEGIN: // from begin
			return position = Math.min(value, input.length());
		case SEEK_GLOBAL_FROM_BEGIN: 
			return position = Math.max(value - getBeginLocation(), 0);
		case SEEK_RELATIVE:
			return position = Math.min(position + value, input.length());
		case SEEK_FROM_END:
			return position = Math.max(0, input.length() - value);
		}
		return position;
	}

	@Override
	public int getBeginLocation() {
		return beginPos != -1 ? this.beginPos : 0;
	}
	
	@Override
	public void setBeginLocation(int value) {
		if (value != getBeginLocation()) {
			localInputDirty = true;
			beginPos = value;
		}
	}

	@Override
	public int getEndLocation() {
		return Math.max(endPos != -1 || input == null ? this.endPos : input.length(), getGlobalPosition());
	}

	@Override
	public void setEndLocation(int value) {
		if (value != getEndLocation()) {
			localInputDirty = true;
			this.endPos = value;
		}
	}

	public IExecutionContext getContext() {
		return context;
	}

	public void setContext(IExecutionContext context) {
		this.context = context;
	}

	public void setMatched(boolean matched) {
		this.matched = matched;
	}

	public boolean isMatched() {
		return matched;
	}

	@Override
	public void updateEndLocation(int value) {
		setEndLocation(Math.max(value, getEndLocation()));
	}

	public DeslPattern getPattern() {
		return pattern;
	}

	public void setPattern(DeslPattern pattern) {
		this.pattern = pattern;
	}
	
	@Override
	public int getMatchedLength() {
		return isMatched() ? getEndLocation() - getBeginLocation() : 0;
	}

	@Override
	public void intialize() {
		
	}

	@Override
	public void setReturnedResult(Object value) {
		this.returnedResult = value;
	}

	@Override
	public Object getReturnedResult() {
		return returnedResult;
	}

	@Override
	public void setArguments(ArgumentSet options) {
		this.arguments = options;
	}

	@Override
	public ArgumentSet getArguments() {
		return this.arguments;
	}
	
	/*@Override
	public Object get(String fieldName) {
		throw new RuntimeException(String.format("Member '%s' is not found in pattern '%s'",
				fieldName, getPattern().getName()));
	}
	
	@Override
	public void set(String fieldname, Object value) {
		throw new RuntimeException(String.format("Member '%s' is not found in pattern '%s'",
				fieldname, getPattern().getName()));
	}*/
}
